package galaxies.starRegions;

import java.util.ArrayList;

import com.jme3.math.Vector2f;

/*
 * Dimension data used to place stars in a particular arm segment.
 * Holds ideal parameters of the star region
 */
public class StarRegionSpiralArmModel {

	private double shortDim;
	private double longDim;
	private double stopLongDim; //cut-off point for the segment.
	//private double area;
	private int numStars;
	
	private Vector2f location = new Vector2f().zero();
	private double rotation = 0.0; //rotation in space around core
	private double offSetRotation = 0.0; //rotation away from main arm
	private Vector2f offSetTranslation = new Vector2f().zero();
	
	private ArrayList<Vector2f> bounds = new ArrayList<Vector2f>();
	
	public StarRegionSpiralArmModel(double longDim, double shortDim, double stopLongDim) {
		this.shortDim = shortDim;
		this.longDim = longDim;
		this.stopLongDim = stopLongDim;		
	}	

	
	/*
	 * Derives a rough array of points around the boundary of this region, centered at (0,0) and facing up
	 */
	public void computeBounds() {
		bounds.clear();
		float y, x;
		double resolution = 1000; //number of points on each side of the half-ellipse
		double baseResolution = 200; //number of points on the base of the half-ellipse
		
		float xStep = (float) (shortDim/resolution);		
		float baseStep = (float) (shortDim/baseResolution);
		ArrayList<Vector2f> leftPoints = new ArrayList<Vector2f>();
		ArrayList<Vector2f> rightPoints = new ArrayList<Vector2f>();
		
		//ArrayList<Vector2f> points = new ArrayList<Vector2f>();
		
		//fill in base (y = 0, x varies)
		for (x = (float) (-shortDim+baseStep); x <= 0; x+=baseStep) {
			leftPoints.add(0, new Vector2f(x,0));
			rightPoints.add(new Vector2f(-x,0));
		}
		
		//calculate y = 0, x = shortDim first (edge of half-ellipse base)
		x = (float) -shortDim;
		y = 0;//(float) (longDim*Math.sqrt(1 - x*x/(shortDim*shortDim)));
		
		leftPoints.add(new Vector2f(x,y));
		rightPoints.add(0, new Vector2f(-x,y));
		
		//boolean check;
		
		int i = 1;
		for (x = (float) (-shortDim+xStep); x <= 0; x+=xStep) {
			
			//check = false;
			
			//x += xStep;//*i;			
			y = (float) (longDim*Math.sqrt(1 - x*x/(shortDim*shortDim)));
			
			if (y > stopLongDim) {
				y = (float) stopLongDim;
				//check = true;
			}
			
//			//Check if there are any repeated points, due to stopLongDim cutoff.
//			if (check) {
//				for (Vector2f point : topPoints) {
//					if (x == point.x) {
//						if (y == point.y) {
//							//don't do anything, point already exists
//						}
//						
//					}
//				}				
//			}
			//else {
				leftPoints.add(new Vector2f(x,y));
				rightPoints.add(0, new Vector2f(-x,y)); //shifts all elements to the right by one, adding in reverse order to maintain clockwise point list
			//}
				
				
				i++;
		}
		
//		System.out.println("ShortDim= " + shortDim);
//		System.out.println("LongDim= " + longDim);
//		
//		for (int j = 0; j < leftPoints.size(); j++) {
//			Vector2f pointLeft = leftPoints.get(j);			
//			System.out.println("Left points (x,y) " + pointLeft.x + " " + pointLeft.y);
//			
//		}
//		
//		for (int k = 0; k < rightPoints.size(); k++) {
//			Vector2f pointRight = rightPoints.get(k);
//			System.out.println("Right points (x,y) " + pointRight.x + " " + pointRight.y);
//		}
		
		bounds.addAll(leftPoints);
		bounds.addAll(rightPoints); //right side points are in reverse order, so a simple addAll works.
		
		rotateBounds(-Math.PI/2);
		
		rotateBounds(this.rotation);
		translateBounds(this.location);		
	}
	
	private void rotateBounds(double rotation) {
		//System.out.println("Rotation= " + rotation);
		Vector2f tempPoint = new Vector2f();
		for (Vector2f point: bounds) {
			tempPoint.x = point.x;
			tempPoint.y = point.y;
			
			point.x = (float) (tempPoint.x*Math.cos(rotation) - tempPoint.y*Math.sin(rotation));
			point.y = (float) (tempPoint.x*Math.sin(rotation) + tempPoint.y*Math.cos(rotation));
			
			//System.out.println("rot (X,Y)= " + point.x + " " + point.y);			
		}		
	}
	
	private void translateBounds(Vector2f translation) {	
		//System.out.println("Translation= " + translation.x + " " + translation.y);
		for (Vector2f point : bounds) {
			point.x = point.x + translation.x;
			point.y = point.y + translation.y;
			
			//System.out.println("Trans (X,Y)= " + point.x + " " + point.y);			
		}				
	}
	
	public ArrayList<Vector2f> getBounds() {
		return this.bounds;
	}
	
	public void setBounds(ArrayList<Vector2f> bounds) {
		this.bounds = bounds;
	}
	
	//public double getArea() {
	//	return this.area;
	//}
	
	public double getShortDim() {
		return this.shortDim;
	}
	
	public double getLongDim() {
		return this.longDim;		
	}
	
	public double getStopLongDim() {
		return this.stopLongDim;
	}
	
	public void setLocation(Vector2f location) {
		this.location = location.add(offSetTranslation);
		computeBounds();
	}
	
	public Vector2f getLocation() {
		return this.location;
	}
	
	public int getNumStars() {
		return this.numStars;
	}
	
	public void setNumStars(int numStars) {
		this.numStars = numStars;
	}
	
	public void setRotation(double rotation) {
		this.rotation = rotation + offSetRotation;
		computeBounds();
	}
	
	public double getRotation() {
		return this.rotation;
	}
	
	public void setOffsetRotation(double rotation) {
		this.offSetRotation = rotation;		
	}
	
	public double getOffsetRotation() {
		return this.offSetRotation;
	}
	
	public void setOffsetTranslation(Vector2f translation) {
		this.offSetTranslation.x = translation.x;
		this.offSetTranslation.y = translation.y;
	}
	
	public Vector2f getOffsetTranslation() {
		return this.offSetTranslation;
	}
	
}
